<!--
* @author luguoxiang
* @date 2021-09-07
* 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
-->
<template>
  <t-form ref="formRef" class="lg-form" :data="modelInner" v-bind="$attrs">
    <grid-component v-bind="gridProps">
      <slot name="prepend" :data="modelInner"></slot>
      <item-component v-for="x in options" :key="x.field" :initialized="x.initialized">
        <template v-for="(x, k) in x.slots" #[k]="scope">
          <slot :name="x" v-bind="scope"></slot>
        </template>
        <template #default="scope">
          <slot v-if="x.defaultSlot" :name="x.defaultSlot" v-bind="scope" :data="modelInner" :field="x.field"></slot>
          <component :is="x.component" v-else v-bind="scope.componentProps" v-model="modelInner[x.field]" />
        </template>
      </item-component>
      <slot name="append" :data="modelInner"></slot>
    </grid-component>
  </t-form>
</template>

<script lang="ts" setup>
import { computed, ref, watch } from 'vue';
import { FormItemProps, Row, ColProps, RowProps } from 'tdesign-vue-next';
import { Dynamic, LgGrid, IFormSchema, IConfigSchema, IComponentProps } from '@/soar';
import { getForms } from './utils';
import { LgFormProps, LgGridProps } from '../types';
import ColItem from './ColItem.vue';
import DivItem from './DivItem.vue';
// 接收事件
interface Props<T> extends LgFormProps<T> {
  /**
   * 表单配置
   */
  schema: IFormSchema<T>[] | IConfigSchema<T>[];
  /**
   * 初始数据
   */
  data?: any;
  /**
   * 是否是更新
   */
  isUpdate?: boolean;
  /**
   * 宫格类型，lg：使用LgGrid，rw：使用 t-row t-col
   */
  gridType?: 'lg' | 'rw';
  /**
   * LgGrid 宫格配置属性
   */
  gridProps?: LgGridProps | RowProps;
  /**
   * 列配置属性
   */
  colProps?: IComponentProps | ColProps;
  /**
   * t-form-item 配置属性
   */
  formItemProps?: FormItemProps;
}
// 接收属性
const props = withDefaults(defineProps<Props<unknown>>(), {
  gridProps: {
    width: 400,
    gap: [12, 16],
  },
});

const ItemComponent = computed(() => (props.gridType === 'rw' ? ColItem : DivItem));
const GridComponent = computed(() => (props.gridType === 'rw' ? Row : LgGrid));

const formRef = ref();
const modelInner = ref<any>({});
// 动态函数
let dynamicList: Dynamic<any, any>[] = [];
// 初始化配置
const options = computed(() => {
  const { colProps, formItemProps } = props; // 默认列配置
  const list: any[] = getForms(props.schema);
  const dynamics: Dynamic<any, any>[] = [];

  for (const x of list) {
    // 生成key
    // x.key ??= nextId();
    const { slots } = x;
    if (slots.default) {
      x.defaultSlot = slots.default;
      delete slots.default;
    }
    /**
     * 子组件初始化回调注册
     * @param api
     */
    x.initialized = (api: { [p: string]: Function }) => {
      x.itemApi = api;
      // 初始化值
      if (typeof x.colProps !== 'function') {
        x.itemApi.updateCol({ ...colProps, ...x.colProps });
      } else {
        x.itemApi.updateCol(colProps);
      }
      if (typeof x.formItemProps !== 'function') {
        x.itemApi.updateFormItem({ name: x.field, label: x.label, ...formItemProps, ...x.formItemProps });
      } else {
        x.itemApi.updateFormItem(formItemProps);
      }
      if (typeof x.componentProps !== 'function') {
        x.itemApi.updateProps(x.componentProps);
      }
      if (x.disabled && typeof x.disabled !== 'function') {
        x.itemApi.updateProp('disabled', x.disabled);
      }
      if (x.rules && typeof x.rules !== 'function') {
        x.itemApi.updateRules(x.rules);
      }
      if (x.hidden && typeof x.hidden !== 'function') {
        x.itemApi.updateHidden(x.hidden);
      }
    };
    // 处理 动态配置
    if (typeof x.vif === 'function') {
      dynamics.push((params) => {
        x.if = x.vif(params);
        x.itemApi.updateIf(x.if);
      });
    }
    if (typeof x.hidden === 'function') {
      x.dHidden = x.hidden;
      dynamics.push((params) => {
        x.hidden = x.dHidden(params);
        x.itemApi.updateHidden(x.hidden);
      });
    }
    if (typeof x.colProps === 'function') {
      dynamics.push((params) => {
        x.itemApi.updateCol({ ...colProps, ...x.colProps(params) });
      });
    }
    if (typeof x.formItemProps === 'function') {
      dynamics.push((params) => {
        x.itemApi.updateFormItem({ name: x.field, label: x.label, ...formItemProps, ...x.formItemProps(params) });
      });
    }
    if (typeof x.componentProps === 'function') {
      dynamics.push((params) => {
        x.itemApi.updateProps(x.componentProps(params));
      });
    }
    // 处理 disabled
    if (typeof x.disabled === 'function') {
      dynamics.push((params) => {
        x.itemApi.updateProp('disabled', x.disabled(params));
      });
    }
    // 处理 rules
    if (typeof x.rules === 'function') {
      dynamics.push((params) => {
        x.itemApi.updateRules(x.rules(params));
      });
    }
  }
  dynamicList = dynamics;
  return list;
});
// 监听表单字段变化，触发动态配置
function dynamic() {
  const params = { data: modelInner.value, isUpdate: props.isUpdate };
  dynamicList.forEach((x) => x(params));
}
// 监听用户输入
watch(() => modelInner.value, dynamic, { deep: true });
watch(
  () => props.data,
  (v) => {
    modelInner.value = v ?? {};
  },
  { immediate: true },
);
// 对外暴露的api
defineExpose({
  formRef,
  /**
   * 校验表单
   */
  validate(...params): Promise<any> {
    return new Promise((resolve, reject) => {
      formRef.value.validate(...params).then((res) => {
        if (res === true) {
          resolve({ ...modelInner.value });
        } else {
          reject(res);
        }
      });
    });
  },
  /**
   * 重置表单
   * @param params
   */
  reset(...params): unknown {
    return formRef.value.reset(...params);
  },
  /**
   * 清空校验状态
   * @param params
   */
  clearValidate(...params): void {
    formRef.value.clearValidate(...params);
  },
  /**
   * 设置校验信息
   * @param params
   */
  setValidateMessage(...params): void {
    formRef.value.setValidateMessage(...params);
  },
  /**
   * 获取数据
   */
  getData(): any {
    return { ...modelInner.value };
  },
  /**
   * 更新显示数量
   * @param showCount
   */
  updateShowNumber(showCount: number) {
    const list = options.value;
    let count = 0;
    for (let i = 0; i < list.length; i++) {
      const item = list[i];
      if (item.hidden || item.if === false) {
        continue;
      }
      item.itemApi?.updateHidden?.(count >= showCount);
      count++;
    }
  },
});
</script>
<script lang="ts">
export default {
  name: 'LgForm',
};
</script>

<style lang="less" scoped>
:deep(.t-form) {
  padding-top: 20px;
  .t-form__controls-content {
    > :nth-child(n) {
      flex: 1;
    }
  }
}
</style>
